package middleware

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"project1/db"
	"project1/dbmodel"

	"time"

	"github.com/golang-jwt/jwt/v4"
	"github.com/kataras/iris/v12"
)

const (
	TOKEN_MAX_REFRESH_MINUTE = 30 * 1440 // 刷新token最长有效期(一个月有效期，分钟单位)
	// JWT配置
	DesKey = "eccbc87e"
)

var (
	JwtKey = []byte("your_jwt_key")
)

type JWT struct {
	SigningKey []byte
}

type CustomClaims struct {
	UserId int `json:"userId"`
	jwt.RegisteredClaims
}

// CreateToken 创建token
func (j *JWT) CreateToken(claims CustomClaims) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	res, err := token.SignedString(j.SigningKey)
	return res, err
}

// ParseToken 解析token
func (j *JWT) ParseToken(tokenString string) (*CustomClaims, string, error) {
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return j.SigningKey, nil
	})
	//解析claim
	claim, ok := token.Claims.(*CustomClaims)
	if !ok {
		return nil, "", errors.New("Couldn't handle this token")
	}
	if err != nil {
		return nil, "", err
	}
	return claim, "", nil
}

// GenerateToken 登录创建token
func GenerateToken(userId int) (string, error) {
	j := &JWT{JwtKey}
	claims := CustomClaims{
		userId, jwt.RegisteredClaims{
			NotBefore: &jwt.NumericDate{Time: time.Now()},                                             // token当前生效时间
			ExpiresAt: &jwt.NumericDate{Time: time.Now().Add(TOKEN_MAX_REFRESH_MINUTE * time.Minute)}, //过期时间
			Issuer:    "sApi",                                                                         //签发人
		},
	}
	token, err := j.CreateToken(claims)
	return token, err
}

// UserAuth token验证
func UserAuth(c iris.Context) {
	token := c.Request().Header.Get("Authorization")
	if token == "" {
		c.Skip()
		c.JSON(iris.Map{
			"code": 1,
			"msg":  "token缺失",
		})
	} else {
		j := &JWT{JwtKey}
		claimsInfo, newToken, err := j.ParseToken(token)
		fmt.Printf("claimsInfo:%+v newToken:%s err:%v\n", claimsInfo, newToken, err)
		if err != nil {
			c.Skip()
			c.JSON(iris.Map{
				"code": 2,
				"msg":  "登录已过期，请重新登录",
			})

		} else {
			c.Values().Set("userId", claimsInfo.UserId)
			//在响应的header头中加新token
			if newToken != "" {
				c.Header("newToken", newToken)
				// c.ResponseWriter().Header().Add("newToken", newToken)
			}
			c.Next()
		}
	}
}

// 校验账号状态
func CheckAccountStatus(c iris.Context) {
	token := c.Request().Header.Get("Authorization")
	if token == "" {
		c.Next()
		return // token缺失直接跳过
	}
	j := &JWT{JwtKey}
	claimsInfo, _, err := j.ParseToken(token)
	if err != nil {
		c.Skip()
		c.JSON(iris.Map{
			"code": 2,
			"msg":  "登录已过期，请重新登录",
		})
	}
	//获取用户账号状态
	userInfo, err := GetUserStatus(claimsInfo.UserId)
	if err != nil {
		c.Skip()
		c.JSON(iris.Map{
			"code": 3,
			"msg":  err.Error(),
		})
	} else {
		// 校验账号状态
		if userInfo.Status == 2 { // 拉黑 get post都不能访问
			if c.Method() == http.MethodGet || c.Method() == http.MethodPost {
				c.Skip()
				c.JSON(iris.Map{
					"code": 4,
					"msg":  "账号已被拉黑，无法访问此请求",
				})
			}
		} else if userInfo.Status == 3 { // 冻结 只能访问get
			if c.Method() == http.MethodPost {
				c.Skip()
				c.JSON(iris.Map{
					"code": 5,
					"msg":  "账号已被冻结，无法访问此请求",
				})
			}
		}
		c.Next()
	}

}

// 校验请求的账号是否属于超级管理员或管理员
func CheckAdmin(c iris.Context) {
	// 超级管理员或管理员才能访问以下接口
	UrlArray := [...]string{
		// 账号
		"/api/login/getAccountList", // 获取账号列表
		"/api/login/deleteAccount",  // 删除账号
		// 卡密
		"/api/key/generateCard",   // 生成卡密
		"/api/key/deleteCard",     // 删除卡密
		"/api/key/queryCard",      // 查询卡密
		"/api/key/queryCardList",  // 查询卡密列表
		"/api/key/updateCardType", // 修改卡密类型
	}
	for _, v := range UrlArray {
		fmt.Println(c.Request().URL.Path, v)
		if c.Request().URL.Path == v {
			token := c.Request().Header.Get("Authorization")
			if token == "" {
				c.Skip()
				c.JSON(iris.Map{
					"code": 4,
					"msg":  "接口访问失败,请登录",
				})
				return
			}

			j := &JWT{JwtKey}
			claimsInfo, _, err := j.ParseToken(token)
			if err != nil {
				c.Skip()
				c.JSON(iris.Map{
					"code": 2,
					"msg":  "登录已过期，请重新登录",
				})
				return
			}

			//获取用户账号状态
			userInfo, err := GetUserStatus(claimsInfo.UserId)
			if err != nil {
				c.Skip()
				c.JSON(iris.Map{
					"code": 3,
					"msg":  err.Error(),
				})
				return
			} else {
				// 校验账号状态
				if userInfo.RoleId == 1 || userInfo.Status == 2 { // 超级管理员或管理员
					c.Next()
					return
				} else {
					c.Skip()
					c.JSON(iris.Map{
						"code": 4,
						"msg":  "账号无权访问此接口",
					})
					return
				}
			}
		}
	}
	c.Next()
}

// ParseToken 只解析不拦截
func ParseToken(c iris.Context) (user dbmodel.User, err error) {
	token := c.Request().Header.Get("Authorization")
	j := &JWT{JwtKey}
	claimsInfo, _, err := j.ParseToken(token)
	err = db.GormDB.Where("id = ?", claimsInfo.UserId).First(&user).Error
	log.Printf("[获取用户账号状态] 用户id:%d 用户状态:%d\n", user.ID, user.Status)
	if err != nil || user.ID == 0 {
		log.Printf("获取用户账号状态_[%d]未查询到账号_SqlError:%v\n", user.ID, err)
		return user, errors.New("获取用户账号状态失败")
	}
	return user, nil
}

// 获取用户账号信息
func GetUserStatus(userid int) (user dbmodel.User, err error) {
	err = db.GormDB.Where("id = ?", userid).First(&user).Error
	log.Printf("[获取用户账号状态] 用户id:%d 用户状态:%d\n", user.ID, user.Status)
	if err != nil || user.ID == 0 {
		log.Printf("获取用户账号状态_[%d]未查询到账号_SqlError:%v\n", user.ID, err)
		return user, errors.New("获取用户账号状态失败")
	}
	return user, nil
}
